package com.kk.poseidon.common.extension;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Enumeration;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import com.kk.poseidon.common.utils.Holder;

/**
* ExtensionServiceLoader.java
* ServiceLoader功能扩展
*
* @author chengkai
* @date  2017年5月26日 上午11:59:06
*/
public class ExtensionLoader<T> {

    private static final String SERVICES_DIRECTORY = "META-INF/services/";

    private static final String POSEIDON_DIRECTORY = "META-INF/poseidon/";

    private static final String POSEIDON_INTERNAL_DIRECTORY = POSEIDON_DIRECTORY + "internal/";

    private static final ConcurrentMap<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();

    private static final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();

    private Class<?> type;

    public ExtensionLoader(Class<?> type) {
        this.type = type;
    }

    private static <T> boolean withExtensionSPIAnnotation(Class<T> type) {
        return type.isAnnotationPresent(SPI.class);
    }

    @SuppressWarnings("unchecked")
    public static <T> ExtensionLoader<T> getExtensionLoader(Class<T> type) {
        if (type == null) {
            throw new IllegalArgumentException("Extension type is null");
        }
        if (!type.isInterface()) {
            throw new IllegalArgumentException("Extension type (" + type + ") is not interface!");
        }
        if (!withExtensionSPIAnnotation(type)) {
            throw new IllegalArgumentException("Extension type (" + type + ") is not extension, because WITHOUT @" + SPI.class.getName() + " Annotation");
        }

        ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        if (loader == null) {
            EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<>(type));
            loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
        }
        return loader;
    }

    @SuppressWarnings("unchecked")
    public T getExtension(String name) {
        if (name == null || name.length() == 0) {
            throw new IllegalArgumentException("Extension name is null");
        }
        if ("default".equals(name)) {
            // TODO
        }
        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
            cachedInstances.putIfAbsent(name, new Holder<Object>());
            holder = cachedInstances.get(name);
        }
        Object instance = holder.get();
        // 双重检查锁
        if (instance == null) {
            synchronized (holder) {
                instance = holder.get();
                if (instance == null) {
                    instance = null;
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

    private T createExtension(String name) {
        return null;
    }

    private Map<String, Class<?>> getExtensionClasses() {
        return null;
    }

    private Map<String, Class<?>> loadExtensionClasses() {
        return null;
    }

    private void loadFile(Map<String, Class<?>> extensionClasses, String dir) {
        // type在getExtensionLoader()已经赋值过
        String fileName = dir + type.getName();
        try {
            Enumeration<URL> urls = null;
            ClassLoader classLoader = getClassLoader();
            if (classLoader != null) {
                urls = classLoader.getResources(fileName);
            } else {
                urls = ClassLoader.getSystemResources(fileName);
            }
            if (urls != null) {
                while (urls.hasMoreElements()) {
                    URL url = urls.nextElement();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(), "utf-8"));
                    try {
                        String line = null;
                        while ((line = reader.readLine()) != null) {
                            if (line.length() > 0) {
                                String name = "";
                                String className = "";
                                int i = line.indexOf('=');
                                if (i > 0) {
                                    name = line.substring(0, i).trim();
                                    className = line.substring(i + 1).trim();
                                }
                                if (className.length() > 0) {
                                    // system classLoader
                                    Class<?> clazz = Class.forName(className, true, classLoader);
                                    // 判断type是不是clazz的父类
                                    if (!type.isAssignableFrom(clazz)) {
                                        throw new IllegalStateException("interface type " + type + ", " + className + " is not subtype of interface");
                                    }
                                }
                            }
                        }
                    } finally {

                    }
                }
            }
        } catch (Throwable e) {
            // TODO: handle exception
        }
    }

    private static ClassLoader getClassLoader() {
        return ExtensionLoader.class.getClassLoader();
    }

}
